﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Web;
using DocumentFormat.OpenXml.Packaging;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using TemplateLibraryConnector.Data;

namespace TemplateLibraryConnector
{
    public class ThumbNail : IHttpHandler
    {

        string sNoThumbPath = NoPreviewAvailableFile("");
        private int width = 0;
        private int height = 0;

        private static string NoPreviewAvailableFile(string fileName)
        {
            if( !string.IsNullOrEmpty(fileName))
                return HttpContext.Current.Request.MapPath("/_layouts/images/"  + SPUtility.MapToIcon(SPContext.Current.Web, fileName,"", IconSize.Size32));
            else
            {
                return HttpContext.Current.Request.MapPath("/_layouts/images/erroricon.png");
            }
        }

        //Keeps the IHttpHandler in memory, so as not to instantiate it on every request.
        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            width = context.Request["width"] != null ? Int32.Parse(context.Request["width"]) : -1;
            height = context.Request["height"] != null ? Int32.Parse(context.Request["height"]) : -1;


            if (context.Request["FilePath"] != null)
            {
                var path = (context.Request["FilePath"]);

                using (var templateHubSite = TemplateLibraryUtility.GetDocumentLibrarySite(path))
                {
                    using (var templateHubWeb = TemplateLibraryUtility.GetDocumentLibraryWeb(path, templateHubSite))
                    {
                        var item = templateHubWeb.GetListItem(path);
                        var fileExt = Path.GetExtension(item.File.Name.ToLower());
                        sNoThumbPath = NoPreviewAvailableFile(path);
                        var fileStream = item.File.OpenBinaryStream(SPOpenBinaryOptions.SkipVirusScan);

                        //Checks for all office XML file extensions
                        switch (fileExt)
                        {
                            //Word Document
                            case ".docx":
                            //Macro-enabled Word document
                            case ".docm":
                                {
                                    UpdateWordThumbnails(fileStream);
                                    break;
                                }

                            //Word Template
                            case ".dotx":
                            //Macro-enabled Word template
                            case ".dotm":
                                {
                                    UpdateWordTemplateThumbnails(fileStream);
                                    break;
                                }

                            //Powerpoint Presentation
                            case ".pptx":
                            //Macro-enabled Powerpoint Presentation
                            case ".pptm":
                            //Powerpoint Template
                            case ".potx":
                            //Macro-enabled Powerpoint Template
                            case ".potm":
                            //Macro-enabled Powerpoint add-in
                            case ".ppam":
                            //Powerpoint Show
                            case ".ppsx":
                            //Macro-enabled Powerpoint Show
                            case ".ppsm":
                            //Powerpoint Slide
                            case ".sldx":
                            //Macro-enabled Powerpoint Slide
                            case ".sldm":
                            //Office Theme
                            case ".thmx":
                                {
                                    UpdatePowerPointThumbnails(fileStream);
                                    break;
                                }

                            //Excel Workbook
                            case ".xlsx":
                            //Macro-enabled Excel Workbook
                            case ".xlsm":
                            //Excel Template
                            case ".xltx":
                            //Macro-enabled Excel Template
                            case ".xltm":
                            //Excel Non-XML binary workbook (untested, will most likely bomb)
                            case ".xlsb":
                            //Macro-enabled Excel add-in
                            case ".xlam":
                                {
                                    UpdateExcelThumbnails(fileStream);
                                    break;
                                }
                            default:
                                {
                                    Image thumbBitmap = new Bitmap(sNoThumbPath);
                                    context.Response.ContentType = "image/Png";
                                    SaveImageToHttpStream(thumbBitmap);
                                    break;
                                }

                        }
                    }
                }
            }
            else
            {
                Image thumbBitmap = new Bitmap(sNoThumbPath);

                if (context.Request["thumb"] != null && context.Request["thumb"] == "no")
                {
                    SaveImageToHttpStream(thumbBitmap);
                }
                else
                {
                    if (width != -1 && width < thumbBitmap.Width)
                        thumbBitmap = ResizeImage(width, thumbBitmap);
                    context.Response.ContentType = "image/Png";
                    SaveImageToHttpStream(thumbBitmap);
                }
            }
        }
            

        private void UpdateThumbnail(ThumbnailPart tn, ThumbnailPartType tnType)
        {
            Image sourceThumbnail;
            if (tn != null)
            {
                var thumbnailStream = tn.GetStream(FileMode.Open, FileAccess.Read);
                
                if (tnType == ThumbnailPartType.Emf || tnType == ThumbnailPartType.Wmf)
                    sourceThumbnail = new Metafile(thumbnailStream);
                else
                    sourceThumbnail = new Bitmap(thumbnailStream);
            }
            else
            {
                sourceThumbnail = new Bitmap(sNoThumbPath);
            }

            if (width != -1 && width < sourceThumbnail.Width)
                sourceThumbnail = ResizeImage(width, sourceThumbnail);
            HttpContext.Current.Response.ContentType = "image/" + tnType;

            SaveImageToHttpStream(sourceThumbnail);

        }

        private static void SaveImageToHttpStream(Image sourceThumbnail)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                sourceThumbnail.Save(ms, ImageFormat.Png);
                ms.WriteTo(HttpContext.Current.Response.OutputStream);
                sourceThumbnail.Dispose();
            }
        }

        private Image ResizeImage( int newWidth, Image image)
        {
            var heightMultiplier = (float)image.Width/image.Height;
            return ResizeImage(newWidth, Convert.ToInt32(newWidth * heightMultiplier), image);

        }

        private Image ResizeImage(int newWidth, int newHeight, Image image)
        {
            var thumbnailBitmap = new Bitmap(newWidth, newHeight);

            var thumbnailGraph = Graphics.FromImage(thumbnailBitmap);

            thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
            thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
            thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;

            var imageRectangle = new Rectangle(0, 0, newWidth, newHeight);
            thumbnailGraph.DrawImage(image, imageRectangle);

            thumbnailGraph.Dispose();
            return thumbnailBitmap;
        }

        


        private void UpdateWordThumbnails(Stream fileStream)
        {
            using (var wpDocFile = WordprocessingDocument.Open(fileStream, true))
            {
                UpdateThumbnail(wpDocFile.ThumbnailPart, ThumbnailPartType.Wmf);
            }
        }
        
        private void UpdateWordTemplateThumbnails(Stream fileStream)
        {
            using (var wpDocTemplate = WordprocessingDocument.Open(fileStream, true))
            {
                UpdateThumbnail(wpDocTemplate.ThumbnailPart, ThumbnailPartType.Jpeg);
            }
        }

        private void UpdatePowerPointThumbnails(Stream fileStream)
        {
            using (var ppDocFile = PresentationDocument.Open(fileStream, true))
            {
                UpdateThumbnail(ppDocFile.ThumbnailPart, ThumbnailPartType.Jpeg);
            }
        }

        private void UpdateExcelThumbnails(Stream fileStream)
        {
            using (var xlDocFile = SpreadsheetDocument.Open(fileStream, true))
            {
                UpdateThumbnail(xlDocFile.ThumbnailPart, ThumbnailPartType.Wmf);
            }
        }

        public bool ThumbCallback()
        {
            return false;
        }
    }
}